//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.1.0
#include "esp8266_driver.h"


static uint8_t ESP8266_Tx_Buf[ESP8266_Max_Buf_Count] = { 0 };
static uint8_t ESP8266_Rx_Buf[ESP8266_Max_Buf_Count] = { 0 };

/**********************驱动初始化配置*********************/
static const WHT_UART_Config_t wht_config =
{
    .Name = UART_3,
    .Bps = 115200,
    .PreemptionPriority = 15,
    .SubPriority = 0,
};
static WHT_UART_Cache_t wht_cache =
{
    .Rx_Buf_Size = ESP8266_Max_Buf_Count,
    .Rx_Count = 0,
    .Rx_Buf = (uint8_t*)ESP8266_Rx_Buf,
};
static volatile uint32_t* ESP8266_RST_State = NULL;
static volatile uint32_t* ESP8266_EN_State = NULL;
static void WHT_ESP8266_Driver_GPIO_Init(void)
{
    WHT_GPIO_BSP.WHT_Set_Clock(ESP8266_RST_GPIO_PORT, ENABLE);
    WHT_GPIO_BSP.WHT_Set_State(ESP8266_RST_GPIO_PORT, ESP8266_RST_GPIO_PIN, Hig);
    WHT_GPIO_BSP.WHT_Set_Mode(ESP8266_RST_GPIO_PORT, ESP8266_RST_GPIO_PIN, Mode_Out_PP);
    WHT_GPIO_BSP.WHT_Config_Bit_Input(ESP8266_RST_GPIO_PORT, ESP8266_RST_GPIO_PIN, &ESP8266_RST_State);

    WHT_GPIO_BSP.WHT_Set_Clock(ESP8266_EN_GPIO_PORT, ENABLE);
    WHT_GPIO_BSP.WHT_Set_State(ESP8266_EN_GPIO_PORT, ESP8266_EN_GPIO_PIN, Low);
    WHT_GPIO_BSP.WHT_Set_Mode(ESP8266_EN_GPIO_PORT, ESP8266_EN_GPIO_PIN, Mode_Out_PP);
    WHT_GPIO_BSP.WHT_Config_Bit_Output(ESP8266_EN_GPIO_PORT, ESP8266_EN_GPIO_PIN, &ESP8266_EN_State);
}

static void WHT_ESP8266_Driver_Init(void)
{
    WHT_ESP8266_Driver_GPIO_Init();
    WHT_UART_BSP.WHT_Register(&wht_config, &wht_cache);
    WHT_UART_BSP.WHT_Config(&wht_config, &wht_cache);
    WHT_UART_BSP.WHT_DMA_Receive(&wht_cache);
}
/**********************驱动初始化配置*********************/


static ErrorStatus WHT_ESP8266_Driver_Puts(const char* tx_buf, uint32_t send_length)
{
    if ((send_length > sizeof(ESP8266_Tx_Buf)) || (send_length == 0))
        return ERROR;
    while (wht_cache.Info->Tx_State == UART_Tx_Busy);//等待发送完成
    wht_cache.Tx_Count = send_length;
    memcpy((void*)ESP8266_Tx_Buf, (const void*)tx_buf, send_length);
    #ifdef ESP8266_Task_Delay
        TickType_t Tick_Count = send_length * 10 * 1000  / wht_config.Bps / portTICK_RATE_MS;//单位ms/Tick

        if (Tick_Count)
        {
            WHT_UART_BSP.WHT_DMA_Send(&wht_cache);
            vTaskDelay(Tick_Count);
        }
        else
        {
            WHT_UART_BSP.WHT_Send(&wht_cache);
        }
    #else
        WHT_UART_BSP.WHT_Send(&wht_config);
    #endif // ESP8266_Task_Delay
    while (wht_cache.Info->Tx_State == UART_Tx_Busy);//等待发送完成
    return SUCCESS;
}
static ErrorStatus WHT_ESP8266_Driver_Gets(char** rx_buf, uint32_t* receive_length)
{
    if ((wht_cache.Info->Rx_State == UART_Rx_Idle) && (wht_cache.Rx_Count != 0))//表示接收完成
    {
        *rx_buf = (char*)ESP8266_Rx_Buf;
        *receive_length = wht_cache.Rx_Count;
        wht_cache.Rx_Count = 0;                      //清0防止多处理
  
        WHT_UART_BSP.WHT_DMA_Receive(&wht_cache);      //接收使用DMA技术
        return SUCCESS;
    }
    else
        return ERROR;
}


/*
AT指令均已\r\n为结束符，ESP8266检测到后才会解析上几次发送的数据，故AT指令可以分批次发送
*/
static ErrorStatus WHT_ESP8266_Driver_Check_OK(char** rx_buf, uint32_t* rx_length)
{
    uint32_t wait_time;

    for (wait_time = 0; wait_time < 300; wait_time++)      //最长等待3秒
    {
        #ifdef ESP8266_Task_Delay
            vTaskDelay(10 / portTICK_RATE_MS);
        #else
            WHT_Delay_ms(10);
        #endif // ESP8266_Task_Delay
        if (WHT_ESP8266_Driver_Gets(rx_buf, rx_length) != ERROR)
        {
            *rx_buf[*rx_length] = '\0';
            if (strstr((const char*)(*rx_buf), "OK") != NULL) //检测到OK字样
                return SUCCESS;
            else
                break;
        }
    };
    return ERROR;
}

static ErrorStatus WHT_ESP8266_Driver_Execute_Cmd(WHT_WIFI_AT_Execute_Cmd_enum cmd_code)//AT执行指令
{
    char** rx_buf;
    uint32_t rx_length;
    ErrorStatus state = ERROR;

    switch (cmd_code)
    {
    case WIFI_AT_Execute_Test:         //测试指令
        state = WHT_ESP8266_Driver_Puts("AT\r\n", 4);
        break;
    case WIFI_AT_Execute_Reset:        //模块复位
        state = WHT_ESP8266_Driver_Puts("AT+RST\r\n", 8);
        break;
    case WIFI_AT_Execute_CWQAP:        //退出与AP的连接
        state = WHT_ESP8266_Driver_Puts("AT+CWQAP\r\n", 10);
    case WIFI_AT_Execute_CIPCLOSE:     //单路连接时使用，关闭TCP或UDP
        state = WHT_ESP8266_Driver_Puts("AT+CIPCLOSE\r\n", 13);
    case WIFI_AT_Execute_CIPSEND:      //进入透传，会先返回字符"\r\n>"，当收到一个包"+++"后退出，每包数据以20ms间隔区分
        state = WHT_ESP8266_Driver_Puts("AT+CIPSEND", 10);
        break;
    default:
        return state;
    }
    if (state != ERROR)
    {
        state = WHT_ESP8266_Driver_Check_OK(rx_buf, &rx_length);
        if (cmd_code == WIFI_AT_Execute_CIPSEND)
        {
            state = SUCCESS;//不判断字符'>'了。
        }
    }
    return state;
}
static ErrorStatus WHT_ESP8266_Driver_Query_Cmd(WHT_WIFI_AT_Query_Cmd_enum cmd_code, char** rx_buf, uint32_t* rx_length)//AT查询指令
{
    ErrorStatus state = ERROR;

    switch (cmd_code)
    {
    case WIFI_AT_Query_GMR:                         //查询软件版本信息
        state = WHT_ESP8266_Driver_Puts("AT+GMR\r\n", 8);
        break;
    case WIFI_AT_Query_CWMODE:                     //查询当前模块的模式
        state = WHT_ESP8266_Driver_Puts("AT+CWMODE?\r\n", 12);
        break;
    case WIFI_AT_Query_CWJAP:                      //返回当前选择的AP的SSID
        state = WHT_ESP8266_Driver_Puts("AT+CWJAP?\r\n", 11);
        break;
    case WIFI_AT_Query_CWLAP:                      //查询当前可用AP
        state = WHT_ESP8266_Driver_Puts("AT+CWLAP\r\n", 10);
        break;
    case WIFI_AT_Query_CWSAP:                      //查询当前AP参数
        state = WHT_ESP8266_Driver_Puts("AT+CWSAP?\r\n", 11);
        break;
    case WIFI_AT_Query_CWLIF:                      //查询已接入设备的IP
        state = WHT_ESP8266_Driver_Puts("AT+CWLIF\r\n", 11);
        break;
    case WIFI_AT_Query_CIPSTATUS:                  //查询当前模块的连接状态和连接参数
        state = WHT_ESP8266_Driver_Puts("AT+CIPSTATUS\r\n", 14);
        break;
    case WIFI_AT_Query_CIFSR:                      //查询本地IP地址
        state = WHT_ESP8266_Driver_Puts("AT+CIFSR\r\n", 10);
        break;
    case WIFI_AT_Query_CIPMODE:                    //查询模块传输模式
        state = WHT_ESP8266_Driver_Puts("AT+CIPMODE?\r\n", 13);
        break;
    case WIFI_AT_Query_CIPSTO:                    //查询服务器超时时间
        state = WHT_ESP8266_Driver_Puts("AT+CIPSTO?\r\n", 12);
        break;
    default:
        return state;
    }
    if (state != ERROR)
        state = WHT_ESP8266_Driver_Check_OK(rx_buf, rx_length);
    return state;
}
static ErrorStatus WHT_ESP8266_Driver_Set_Cmd(WHT_WIFI_AT_Set_Cmd_enum cmd_code, char* tx_buf, uint32_t tx_length)//AT设置指令操作
{
    char** buf;
    ErrorStatus state = ERROR;

    if ((tx_length == 0) || (tx_length > ESP8266_Max_Buf_Count))
        return state;
    switch (cmd_code)
    {
    case WIFI_AT_Set_CWMODE:         //设置当前模块的模式，重启生效
        state = WHT_ESP8266_Driver_Puts("AT+CWMODE=", 10);
        break;
    case WIFI_AT_Set_CWJAP:          //加入AP
        state = WHT_ESP8266_Driver_Puts("AT+CWJAP=", 9);
        break;
    case WIFI_AT_Set_CWSAP:          //设置AP模式下的参数
        state = WHT_ESP8266_Driver_Puts("AT+CWSAP=", 9);
        break;
    case WIFI_AT_Set_CIPSTART:       //建立TCP连接或注册UDP端口号，单连接和多连接
        state = WHT_ESP8266_Driver_Puts("AT+CIPSTART=", 12);
        break;
    case WIFI_AT_Set_CIPSEND:        //发送指定长度的数据，单连接和多连接 会先返回字符"\r\n>",之后发送数据即可
        state = WHT_ESP8266_Driver_Puts("AT+CIPSEND=", 11);
        break;
    case WIFI_AT_Set_CIPCLOSE:       //id=5则关闭关闭TCP或UDP
        state = WHT_ESP8266_Driver_Puts("AT+CIPCLOSE=", 11);
        break;
    case WIFI_AT_Set_CIPMUX:         //启动多连接，单路连接或多路连接，只有当连接都断开后才能更改，如果开启过server需要重启模块
        state = WHT_ESP8266_Driver_Puts("AT+CIPMUX=", 10);
        break;
    case WIFI_AT_Set_CIPSERVER:      //关闭server需要重启,开启server需要"AT+CIPMUX=1"时才能开启服务器
        state = WHT_ESP8266_Driver_Puts("AT+CIPSERVER=", 13);
        break;
    case WIFI_AT_Set_CIPMODE:        //设置模块传输模式
        state = WHT_ESP8266_Driver_Puts("AT+CIPMODE=", 11);
        break;
    case WIFI_AT_Set_CIPSTO:         //设置服务器超时时间,0~28800
        state = WHT_ESP8266_Driver_Puts("AT+CIPSTO=", 10);
        break;
    default:
        return state;
    }
    if (state != ERROR)
    {
        state = WHT_ESP8266_Driver_Puts(tx_buf, tx_length);
        if (state != ERROR)
        {
            state = WHT_ESP8266_Driver_Puts("\r\n", 2);
            if (state != ERROR)
                state = WHT_ESP8266_Driver_Check_OK(buf, &tx_length);
        }
    }
    //*ESP8266_KEY_State = Low;
    return state;
}


static ErrorStatus WHT_ESP8266_Driver_Transparent_Transmission_Send(const char* tx_buf, uint32_t tx_length)
{
    return WHT_ESP8266_Driver_Puts(tx_buf, tx_length);
}
static ErrorStatus WHT_ESP8266_Driver_Transparent_Transmission_Receive(char** rx_buf, uint32_t* rx_length)
{
    return WHT_ESP8266_Driver_Gets(rx_buf, rx_length);
}

static void WHT_ESP8266_Driver_Reset(void)
{
    *ESP8266_RST_State = Low;
    #ifdef ESP8266_Task_Delay
        vTaskDelay(500 / portTICK_RATE_MS);
    #else
        WHT_Delay_ms(500);
    #endif // ESP8266_Task_Delay
    * ESP8266_RST_State = Hig;
}
static ErrorStatus WHT_ESP8266_Driver_Net_Mode_Choose(WHT_WIFI_Net_Mode_enum mode)
{
    char mode_buf;

    switch (mode)
    {
    case WHT_WIFI_Station:    mode_buf = '1'; break;
    case WHT_WIFI_AP:         mode_buf = '2'; break;
    case WHT_WIFI_Station_AP: mode_buf = '3'; break;
    default:
        return ERROR;
    }
    return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CWMODE, &mode_buf, 1);
    //手册上说重启生效，野火未重启
}
static ErrorStatus WHT_ESP8266_Driver_Join_AP(char* ssid, char* pass_word)//加入AP
{
    uint32_t tx_length;
    char tx_buf[64 + 64];

    tx_length = strlen(ssid) + strlen(pass_word) + 3 + 1 + 3;//测量不含\0
    if (tx_length > sizeof(tx_buf))
        return ERROR;
    sprintf(tx_buf, "\"%s\",\"%s\"", ssid, pass_word);//会拷贝\0
    return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CWJAP, tx_buf, tx_length);
}
static ErrorStatus WHT_ESP8266_Driver_Build_AP(char* ssid, char* pass_word, WHT_WIFI_CHx_enum chx, WHT_WIFI_ECN_enum ecn)//创建WiFi热点
{
    uint32_t tx_length;
    char tx_buf[64 + 64];

    tx_length = strlen(ssid) + strlen(pass_word) + 3 + 1 + 3 + 1 + 1 + 1 + +1;//测量不含\0
    if (chx >= WHT_WIFI_Ch10)
        tx_length++;
    if (tx_length > sizeof(tx_buf))
        return ERROR;
    sprintf(tx_buf, "\"%s\",\"%s\",%d,%d", ssid, pass_word, chx, ecn);//会拷贝\0
    return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CWSAP, tx_buf, tx_length);
}
static ErrorStatus WHT_ESP8266_Driver_MultipleId(FunctionalState state)//启动多连接
{
    char mode_buf;

    mode_buf = state == ENABLE ? '1' : '0';
    return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPMUX, &mode_buf, 1);
}
static ErrorStatus WHT_ESP8266_Driver_Link_Server(WHT_WIFI_Net_Type_enum type, char* ip, char* port, WHT_WIFI_Net_ID_enum id)//连接外部服务器
{
    uint32_t tx_length;
    char tx_buf[64 + 64];

    tx_length = strlen(ip) + strlen(port) + 6 + 1 + 3 + 1 + 3;//测量不含\0
    if (id >= WHT_WIFI_Single_ID0)
    {
        if (type == WHT_WIFI_TCP)
            memcpy(tx_buf, "\"TCP\",", 7);
        else
            memcpy(tx_buf, "\"UDP\",", 7);
        sprintf(&tx_buf[7], "\"%s\",%s", ip, port);//会拷贝\0
    }
    else
    {
        tx_length += 2;
        if (type == WHT_WIFI_TCP)
            sprintf(tx_buf, "%d,\"TCP\",", id);
        else
            sprintf(tx_buf, "%d,\"UDP\",", id);
        sprintf(&tx_buf[9], "\"%s\",%s", ip, port);//会拷贝\0

    }
    return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPSTART, tx_buf, tx_length);
}
static ErrorStatus WHT_ESP8266_Driver_Set_Server_State(FunctionalState state, char* port, char* timeover)//开启或关闭服务器模式
{
    char tx_buf[16];

    if (state == ENABLE)
    {
        sprintf(tx_buf, "1,%s", port);
        if (WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPSERVER, tx_buf, strlen(port) + 2) != ERROR)
        {
            return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPSTO, timeover, strlen(timeover));
        }
        else
            return ERROR;
    }
    else
    {
        sprintf(tx_buf, "0,%s", port);
        return WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPSERVER, tx_buf, strlen(port) + 2);
    }
}

static uint32_t WHT_ESP8266_Driver_Get_Link_State(void)
{
    char* rx_buf;
    uint32_t rx_length;

    if (WHT_ESP8266_Driver_Query_Cmd(WIFI_AT_Query_CIPSTATUS, &rx_buf, &rx_length) != ERROR)
    {
        if (strstr(rx_buf, "STATUS:2"))
            return 2;
        else if (strstr(rx_buf, "STATUS:3"))
            return 3;
        else if (strstr(rx_buf, "STATUS:4"))
            return 4;
    }
    return 0;
}




static ErrorStatus WHT_ESP8266_Driver_Test_AT_Cmd(void)
{
    if (WHT_ESP8266_Driver_Execute_Cmd(WIFI_AT_Execute_Test) != ERROR)//首次验证AT指令可能有之前的缓存
        return WHT_ESP8266_Driver_Execute_Cmd(WIFI_AT_Execute_Test);  //再次判断AT指令
    else
        return ERROR;
}
static ErrorStatus WHT_ESP8266_Driver_Init_Config(void)
{
    uint32_t count;
    ErrorStatus state;

    #ifdef ESP8266_Task_Delay
        vTaskDelay(2000 / portTICK_RATE_MS);
    #else
        WHT_Delay_ms(2000);
    #endif // ESP8266_Task_Delay
    state = WHT_ESP8266_Driver_Test_AT_Cmd();
    for (count = 0; ; count++)
    {
        if (state == ERROR)
            return state;
        switch (count)
        {
        case 0://对模块复位重启
            state = WHT_ESP8266_Driver_Execute_Cmd(WIFI_AT_Execute_Reset);
            break;
        case 1://Station模式
            state = WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CWMODE, "1", 1);
            break;
        case 2://连接热点
            state = WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CWJAP, "\"WIFI 2.4G\",\"@12345678\"", 23);
            break;
        case 3://禁用多连接
            state = WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPMUX, "0", 1);
            break;
        case 4://连接指定IP服务器
            state = WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPSTART, "\"TCP\",\"192.168.15.219\",8000", 27);
            break;
        case 5://进入透传发送模式
            if (WHT_ESP8266_Driver_Set_Cmd(WIFI_AT_Set_CIPMODE, "1", 1) != ERROR)
                state = WHT_ESP8266_Driver_Execute_Cmd(WIFI_AT_Execute_CIPSEND);
            break;
        default:
            return SUCCESS;
        }
    }
}



void WHT_ESP8266_Driver_Register(WHT_ESP8266_Driver_t* driver)
{
    WHT_ESP8266_Driver_Init();

    driver->WHT_WIFI_Reset               = WHT_ESP8266_Driver_Reset;
    driver->WHT_WIFI_Config              = WHT_ESP8266_Driver_Init_Config;
    driver->WHT_WIFI_Execute_Cmd         = WHT_ESP8266_Driver_Execute_Cmd;
    driver->WHT_WIFI_Query_Cmd           = WHT_ESP8266_Driver_Query_Cmd;
    driver->WHT_WIFI_Set_Cmd             = WHT_ESP8266_Driver_Set_Cmd;
    driver->WHT_Transparent_Transmission_Send    = WHT_ESP8266_Driver_Transparent_Transmission_Send;
    driver->WHT_Transparent_Transmission_Receive = WHT_ESP8266_Driver_Transparent_Transmission_Receive;
}
